home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / prof / ds3100.md / profSubr.c < prev   
C/C++ Source or Header  |  1991-05-30  |  11KB  |  438 lines

  1. /* 
  2.  * prof.c --
  3.  *
  4.  *    Routines for initializing and collecting profile information.
  5.  *
  6.  * Copyright 1986, 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/kernel/prof/ds3100.md/RCS/profSubr.c,v 1.4 91/05/30 15:18:07 kupfer Exp $ SPRITE (DECWRL)";
  18. #endif not lint
  19.  
  20.  
  21. #include "sprite.h"
  22. #include "prof.h"
  23. #include "profInt.h"
  24. #include "dbg.h"
  25. #include "sys.h"
  26. #include "timer.h"
  27. #include "mach.h"
  28. #include "fs.h"
  29. #include "vm.h"
  30.  
  31. extern    int    etext;
  32.  
  33. /*
  34.  * An on/off profiling switch.
  35.  */
  36.  
  37. Boolean profEnabled = FALSE;
  38.  
  39.  
  40. /*
  41.  * A histogram of PC samples is kept for use by gprof. Each sample is a
  42.  * counter that gets incremented when the PC is in the range for the counter.
  43.  */
  44.  
  45. typedef struct {
  46.     Address lowpc;
  47.     Address highpc;
  48.     int        size;
  49. } SampleHdr;
  50.  
  51. static int    pcSampleSize;
  52. static short    *pcSamples;
  53.  
  54. /*
  55.  * PC sampling data structures (shared with _mcount.c).
  56.  */
  57.  
  58. int        profArcListSize;
  59. ProfRawArc    *profArcList;
  60. ProfRawArc    *profArcListFreePtr;
  61. ProfRawArc    *profArcListEndPtr;
  62.  
  63. int        profArcIndexSize;
  64. ProfRawArc    **profArcIndex;
  65.  
  66. /*
  67.  * Flag to indicate if Prof_Init has been called.
  68.  */
  69. static Boolean    init = FALSE;
  70.  
  71.  
  72. /*
  73.  *----------------------------------------------------------------------
  74.  *
  75.  * Prof_Init --
  76.  *
  77.  *    Allocate the profile data structures and initialize the profile timer.
  78.  *    The timer is initialized to automatically start ticking again
  79.  *    once its interrupt line is reset.  The array of counters
  80.  *    for sampling the PC is allocated, as is the table of call
  81.  *    graph arc counts.
  82.  *
  83.  * Results:
  84.  *    None.
  85.  *
  86.  * Side effects:
  87.  *    Uses Vm_RawAlloc.  Each structure is order(textSize).
  88.  *    Sets a flag indicating it has been called.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92.  
  93. void
  94. Prof_Init()
  95. {
  96.     int numInstructions;
  97.  
  98.     /*
  99.      * We estimate the number of instructions in the text
  100.      * by dividing the address range by four....  This determines
  101.      * to PC to index calculations done in mcount and Prof_CollectInfo.
  102.      */
  103.  
  104.     numInstructions = ((unsigned)&etext - (unsigned) mach_CodeStart) >> 
  105.     PROF_INSTR_SIZE_SHIFT;
  106.     printf("Prof_Init: # instructions in kernel = %d\n", numInstructions);
  107.  
  108.     /*
  109.      * The size of the sample array reflects a compression down
  110.      * by the group size.
  111.      */
  112.  
  113.     pcSampleSize = numInstructions / PROF_PC_GROUP_SIZE;
  114.     pcSamples = (short *) Vm_RawAlloc(pcSampleSize * sizeof(short));
  115.  
  116.     /*
  117.      * Allocate an array indexed by PC and containing a pointer
  118.      * to the call graph arc that starts at that PC.  This array is
  119.      * compressed by the arc group size.
  120.      */
  121.     profArcIndexSize = numInstructions >> PROF_ARC_GROUP_SHIFT;
  122. #ifdef MCOUNT
  123.     profArcIndex = 
  124.     (ProfRawArc **) Vm_RawAlloc(profArcIndexSize * sizeof(ProfRawArc *));
  125. #endif
  126.  
  127.     /*
  128.      * The arcList needs an element for every distinct call instruction
  129.      * that gets executed in the kernel.  The size is just a guess.
  130.      */
  131.  
  132.     profArcListSize = numInstructions / PROF_CALL_RATIO;
  133. #ifdef MCOUNT
  134.     profArcList = 
  135.         (ProfRawArc *) Vm_RawAlloc(profArcListSize * sizeof(ProfRawArc));
  136. #endif
  137.  
  138.     init = TRUE;
  139. }
  140.  
  141. /*
  142.  *----------------------------------------------------------------------
  143.  *
  144.  * Prof_Start --
  145.  *
  146.  *    Initialize the profile data structures and the profile timer.
  147.  *    This clears the PC sample counters, the call graph arc counters,
  148.  *    and the index into the list of call graph arc counters.
  149.  *
  150.  *    The interval between profile timer interrupts is defined in 
  151.  *    machRefresh. 
  152.  *
  153.  * Results:
  154.  *    Return status.
  155.  *
  156.  * Side effects:
  157.  *    Profiling is enabled and the data structures are zeroed.
  158.  *
  159.  *----------------------------------------------------------------------
  160.  */
  161.  
  162. ReturnStatus
  163. Prof_Start()
  164. {
  165.     if (!init) {
  166.     Prof_Init();
  167.     }
  168.  
  169.     printf("Starting Profiling.\n");
  170.  
  171.     /*
  172.      * Reset the PC sample counters.
  173.      */
  174.  
  175.     bzero( (Address) pcSamples, pcSampleSize * sizeof(short));
  176.  
  177. #ifdef MCOUNT
  178.     /*
  179.      * Reset the arc pointer list indexed by caller PC.
  180.      */
  181.  
  182.     bzero((Address) profArcIndex, profArcIndexSize * sizeof(ProfRawArc *));
  183.  
  184.     /*
  185.      * Set the free pointers into the arc storage.  Don't have to
  186.      * initialize the arc storage itself because that is done
  187.      * as arc storage is allocated by mcount.
  188.      */
  189.  
  190.     profArcListFreePtr = &profArcList[0];
  191.     profArcListEndPtr = &profArcList[profArcListSize-1];
  192. #endif
  193.     Timer_TimerInit(TIMER_PROFILE_TIMER);
  194.     Timer_TimerStart(TIMER_PROFILE_TIMER);
  195.     profEnabled = TRUE;
  196.  
  197.     return(SUCCESS);
  198. }
  199.  
  200.  
  201. /*
  202.  *----------------------------------------------------------------------
  203.  *
  204.  * Prof_CollectInfo --
  205.  *
  206.  *    Collect profiling information from the stack.
  207.  *
  208.  *
  209.  *    Note: This is an interrupt-level routine.
  210.  *
  211.  * Results:
  212.  *    None.
  213.  *
  214.  * Side effects:
  215.  *    Increment the counter associated with the PC value.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219.  
  220. void
  221. Prof_CollectInfo(pc)
  222.     register unsigned int    pc;    /* Address of PC at sample time. */
  223. {
  224.     register int index;    /* Index into the array of counters */
  225.  
  226.     if (!profEnabled) {
  227.     return;
  228.     }
  229.  
  230.     if (pc >= (unsigned int) mach_CodeStart && pc <= (unsigned int) &etext ) {
  231.     index = (pc - (unsigned int) mach_CodeStart) >> PROF_PC_SHIFT;
  232.     if (index < pcSampleSize) {
  233.         pcSamples[index]++;
  234.     }
  235.     }
  236. }
  237.  
  238.  
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * Prof_End --
  243.  *
  244.  *    Stop the profiling.
  245.  *
  246.  * Results:
  247.  *    Return status.
  248.  *
  249.  * Side effects:
  250.  *    Profiling is disabled.
  251.  *
  252.  *----------------------------------------------------------------------
  253.  */
  254.  
  255. ReturnStatus
  256. Prof_End()
  257. {
  258.     Timer_TimerInactivate(TIMER_PROFILE_TIMER);
  259.        profEnabled = FALSE;
  260.     return(SUCCESS);
  261. }
  262.  
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * Prof_Dump --
  267.  *
  268.  *    Dump out the profiling data to the specified file.
  269.  *
  270.  * Results:
  271.  *    SUCCESS        - the information was dumped to the file.
  272.  *    ?        - return codes from Fs module.
  273.  *
  274.  * Side effects:
  275.  *    Write the profiling data to a file.
  276.  *
  277.  *----------------------------------------------------------------------
  278.  */
  279.  
  280. ReturnStatus
  281. Prof_Dump(dumpName)
  282.     char *dumpName;        /* Name of the file to dump to. */
  283. {
  284.     ReturnStatus    status;
  285.     Fs_Stream        *streamPtr;
  286.     int            fileOffset;
  287.     int            writeLen;
  288. #ifdef MCOUNT
  289.     int            index;
  290.     ProfArc        arc;
  291.     ProfRawArc        *rawArcPtr;
  292. #endif
  293.     SampleHdr        sampleHdr;
  294.  
  295.     status = Fs_Open(dumpName, FS_WRITE|FS_CREATE, FS_FILE, 0666, &streamPtr);
  296.     if (streamPtr == (Fs_Stream *) NIL || status != SUCCESS) {
  297.     return(status);
  298.     }
  299.  
  300.     /*
  301.      * Write out the PC sampling counters.  Note they are preceeded
  302.      * by a header that indicates the PC range and the size of the
  303.      * sampling buffer.  (The size includes the header size...)
  304.      */
  305.  
  306.     sampleHdr.lowpc    = mach_CodeStart;
  307.     sampleHdr.highpc    = (Address) &etext;
  308.     sampleHdr.size    = (pcSampleSize * sizeof(short)) + sizeof(sampleHdr);
  309.  
  310.     {
  311.     int magic = 0x0f0e0001;
  312.     fileOffset = 0;
  313.     writeLen = sizeof(int);
  314.     status = Fs_Write(streamPtr, (Address) &magic, fileOffset, &writeLen);
  315.     if (status != SUCCESS) {
  316.         printf(
  317.             "Prof_Dump: Fs_Write(1) failed, status = %x\n",status);
  318.         goto dumpError;
  319.     }
  320.     }
  321.     fileOffset += writeLen;
  322.     writeLen = sizeof(sampleHdr);
  323.     status = Fs_Write(streamPtr, (Address) &sampleHdr, fileOffset, &writeLen);
  324.     if (status != SUCCESS) {
  325.     printf(
  326.             "Prof_Dump: Fs_Write(1) failed, status = %x\n",status);
  327.     goto dumpError;
  328.     }
  329.     printf("Prof_Dump: pc sample size = %d\n", pcSampleSize);
  330.  
  331.     fileOffset += writeLen;
  332.     writeLen = pcSampleSize * sizeof(short);
  333.     status = Fs_Write(streamPtr, (Address) pcSamples, fileOffset, &writeLen);
  334.     if (status != SUCCESS) {
  335.     printf(
  336.             "Prof_Dump: Fs_Write(2) failed, status = %x\n",status);
  337.     goto dumpError;
  338.     }
  339.  
  340.     fileOffset += writeLen;
  341.  
  342.     /*
  343.      * Write out instantiated arcs.  Loop through the arcIndex index
  344.      * and for each one that has arc storage figure out the PC that
  345.      * corresponds to the arcIndex.  Then dump out an entry for
  346.      * each routine called from that PC.
  347.      */
  348. #ifdef MCOUNT
  349.     for (index = 0 ; index < profArcIndexSize ; index++) {
  350.     rawArcPtr = profArcIndex[index];
  351.  
  352.     /* 
  353.      * Check if rawArcPtr equals an unused value (which is 0 because 
  354.      * profArcIndex is initialized with bzero in Prof_Start).
  355.      */
  356.     if (rawArcPtr == (ProfRawArc *) 0) {
  357.         continue;
  358.     }
  359.  
  360.     /*
  361.      * Reverse the PC to index calculation done in mcount.
  362.      */
  363.     arc.callerPC = mach_CodeStart + (index << PROF_ARC_SHIFT);
  364.  
  365.     do {
  366.         arc.calleePC = rawArcPtr->calleePC;
  367.         arc.count = rawArcPtr->count;
  368.  
  369.         writeLen = sizeof(ProfArc);
  370.         status = Fs_Write(streamPtr, (Address)&arc, fileOffset, &writeLen);
  371.         if (status != SUCCESS) {
  372.         printf(
  373.             "Prof_Dump: Fs_Write(3) failed, status = %x, index = %d\n",
  374.             status, index);
  375.         goto dumpError;
  376.         }
  377.         fileOffset += writeLen;
  378.  
  379.         rawArcPtr = rawArcPtr->link;
  380.         /*
  381.          * Check against NIL pointer here because of initialization
  382.          * in mcount.
  383.          */
  384.     } while (rawArcPtr != (ProfRawArc *)NIL);
  385.     }
  386. #endif
  387.     status = Fs_Close(streamPtr);
  388.     if (status != SUCCESS) {
  389.     printf(
  390.         "Prof_Dump: Fs_Close failed, status = %x\n", status);
  391.     }
  392.     return(status);
  393.  
  394. dumpError:
  395.     (void) Fs_Close(streamPtr);
  396.     return(status);
  397. }
  398.  
  399.  
  400. /*
  401.  *----------------------------------------------------------------------
  402.  *
  403.  * Prof_DumpStub --
  404.  *
  405.  *    This system call dumps profiling information into the specified file.
  406.  *    This is done by making the name of the file accessible, then calling 
  407.  *    Prof_Dump.
  408.  *
  409.  * Results:
  410.  *    SUCCESS        - the file was dumped.
  411.  *    ?        - error returned by Fs module.
  412.  *
  413.  * Side effects:
  414.  *    A file is written.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418.  
  419. ReturnStatus
  420. Prof_DumpStub(pathName)
  421.     char *pathName;        /* The name of the file to write. */
  422. {
  423.     char    newName[FS_MAX_PATH_NAME_LENGTH];
  424.     int        pathNameLength;
  425.  
  426.     /*
  427.      * Copy the name in from user space to the kernel stack.
  428.      */
  429.     if (Proc_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  430.              &pathNameLength) != SUCCESS) {
  431.     return(SYS_ARG_NOACCESS);
  432.     }
  433.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  434.     return(FS_INVALID_ARG);
  435.     }
  436.     return(Prof_Dump(newName));
  437. }
  438.